use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, NotSet, PaginatorTrait, QueryFilter};
use sea_orm::ActiveValue::Set;

use common::ctx::get_db;
use common::error::MyError;
use common::page::{BasePage, PageResult};
use entity::prelude::Resource;
use entity::resource;
use model::resource::{CreateResource, ResourcePage};

use crate::manager::base::BaseManager;

pub struct ResourceManager {}

impl BaseManager<i64, resource::Model, ResourcePage, CreateResource, resource::Model>
    for ResourceManager
{
    async fn list() -> Result<Vec<resource::Model>, MyError> {
        let res = Resource::find().all(&*get_db()?).await?;
        Ok(res)
    }

    async fn page(page: ResourcePage) -> Result<PageResult<resource::Model>, MyError> {
        let mut page_data = page.get_page_data();
        //校验分页数据是否合法
        page_data = page_data.check();
        let mut find = Resource::find();

        if let Some(parent_id) = page.parent_id {
            find = find.filter(resource::Column::ParentId.eq(parent_id));
        }

        if let Some(resource_name) = page.resource_name {
            find = find.filter(resource::Column::ResourceName.like(format!("%{}%", resource_name)));
        }

        if let Some(resource_code) = page.resource_code {
            find = find.filter(resource::Column::ResourceCode.like(format!("%{}%", resource_code)));
        }

        if let Some(resource_type) = page.resource_type {
            find = find.filter(resource::Column::ResourceType.eq(resource_type));
        }

        if let Some(status) = page.status {
            find = find.filter(resource::Column::Status.eq(status));
        }

        if let Some(api_path) = page.api_path {
            find = find.filter(resource::Column::ApiPath.like(format!("%{}%", api_path)));
        }

        if let Some(api_http_method) = page.api_http_method {
            find = find.filter(resource::Column::ApiHttpMethod.eq(api_http_method));
        }

        if let Some(role) = page.role {
            find = find.filter(resource::Column::Role.like(format!("%{}%", role)));
        }

        if let Some(resource_desc) = page.resource_desc {
            find = find.filter(resource::Column::ResourceDesc.like(format!("%{}%", resource_desc)));
        }

        if let Some(resource_root) = page.resource_root {
            find = find.filter(resource::Column::ResourceRoot.eq(resource_root));
        }

        if let Some(resource_action) = page.resource_action {
            find = find.filter(resource::Column::ResourceAction.eq(resource_action));
        }
        let db_conn = &*get_db()?;
        let paginator = find.paginate(db_conn, page_data.page_size);

        //分页查询
        let record = paginator.fetch_page(page_data.page - 1).await?;
        //总条数
        let total = paginator.num_items().await?;
        //返回分页结果
        Ok(PageResult {
            page: page_data.page,
            page_size: page_data.page_size,
            total,
            record,
        })
    }

    async fn info(id: i64) -> Result<Option<resource::Model>, MyError> {
        let res = Resource::find_by_id(id).one(&*get_db()?).await?;
        Ok(res)
    }

    async fn add(form: CreateResource) -> Result<i64, MyError> {
        let resource_name = form
            .resource_name
            .ok_or(MyError::ServerError("资源名称不能为空".to_string()))?;
        let resource_code = form
            .resource_code
            .ok_or(MyError::ServerError("资源编码不能为空".to_string()))?;
        ResourceManager::check_resource_code_exist(resource_code.clone()).await?;
        let model = resource::ActiveModel {
            id: NotSet,
            parent_id: Set(form.parent_id),
            resource_name: Set(Some(resource_name)),
            resource_code: Set(Some(resource_code)),
            resource_type: Set(form.resource_type),
            resource_root: Set(form.resource_root),
            resource_action: Set(form.resource_action),
            order_number: Set(form.order_number),
            url: Set(form.url),
            icon: Set(form.icon),
            status: Set(form.status),
            api_path: Set(form.api_path),
            api_http_method: Set(form.api_http_method),
            role: Set(form.role),
            resource_desc: Set(form.resource_desc),
        }
        .insert(&*get_db()?)
        .await?;
        Ok(model.id)
    }

    async fn update(form: resource::Model) -> Result<i64, MyError> {
        let entity = Resource::find_by_id(form.id)
            .one(&*get_db()?)
            .await?
            .ok_or(MyError::ServerError(format!(
                "user [{:?}] does not exist",
                form.id
            )))?;
        let mut entity: resource::ActiveModel = entity.into();
        if let Some(parent_id) = Option::from(form.parent_id) {
            entity.parent_id = Set(parent_id);
        }
        if form.resource_name.is_some() {
            entity.resource_name = Set(form.resource_name);
        }
        if form.resource_code.is_some() {
            ResourceManager::check_resource_code_exist_and_id_ne(
                form.resource_code.clone().unwrap(),
                form.id,
            )
            .await?;
            entity.resource_code = Set(form.resource_code);
        }
        if form.resource_type.is_some() {
            entity.resource_type = Set(form.resource_type);
        }
        if form.order_number.is_some() {
            entity.order_number = Set(form.order_number);
        }
        if form.url.is_some() {
            entity.url = Set(form.url);
        }
        if form.icon.is_some() {
            entity.icon = Set(form.icon);
        }
        if let Some(status) = Option::from(form.status) {
            entity.status = Set(status);
        }
        if form.api_path.is_some() {
            entity.api_path = Set(form.api_path);
        }
        if form.api_http_method.is_some() {
            entity.api_http_method = Set(form.api_http_method);
        }
        if form.role.is_some() {
            entity.role = Set(form.role);
        }
        if form.resource_desc.is_some() {
            entity.resource_desc = Set(form.resource_desc);
        }
        let result = entity.update(&*get_db()?).await?;
        Ok(result.id)
    }

    async fn delete(id: i64) -> Result<bool, MyError> {
        let res = Resource::delete_by_id(id).exec(&*get_db()?).await?;
        Ok(res.rows_affected == 1)
    }
}

impl ResourceManager {
    pub async fn get_resource_all_list() -> Result<Vec<resource::Model>, MyError> {
        let a = Resource::find()
            .filter(resource::Column::Status.eq(true))
            .all(&*get_db()?)
            .await?;
        Ok(a)
    }

    pub async fn get_resource_list_by_ids(ids: Vec<i64>) -> Result<Vec<resource::Model>, MyError> {
        let res = Resource::find()
            .filter(resource::Column::Id.is_in(ids))
            .all(&*get_db()?)
            .await?;
        Ok(res)
    }

    pub async fn get_menu_resource_list_by_ids(
        ids: Vec<i64>,
    ) -> Result<Vec<resource::Model>, MyError> {
        let res = Resource::find()
            .filter(resource::Column::ResourceType.eq(1))
            .filter(resource::Column::Status.eq(true))
            .filter(resource::Column::Id.is_in(ids))
            .all(&*get_db()?)
            .await?;
        Ok(res)
    }

    pub async fn exist_by_resource_code(resource_code: String) -> Result<bool, MyError> {
        let exist = Resource::find()
            .filter(resource::Column::ResourceCode.eq(resource_code))
            .all(&*get_db()?)
            .await?
            .len()
            > 0;
        Ok(exist)
    }

    pub async fn exist_by_resource_code_and_id_ne(
        resource_code: String,
        id: i64,
    ) -> Result<bool, MyError> {
        let exist = Resource::find()
            .filter(resource::Column::ResourceCode.eq(resource_code))
            .filter(resource::Column::Id.ne(id))
            .all(&*get_db()?)
            .await?
            .len()
            > 0;
        Ok(exist)
    }

    pub async fn check_resource_code_exist(resource_code: String) -> Result<String, MyError> {
        if ResourceManager::exist_by_resource_code(resource_code.clone()).await? {
            Err(MyError::ServerError(format!(
                "资源编码[{}]已存在",
                resource_code
            )))
        } else {
            Ok(resource_code)
        }
    }

    pub async fn check_resource_code_exist_and_id_ne(
        resource_code: String,
        id: i64,
    ) -> Result<String, MyError> {
        if ResourceManager::exist_by_resource_code_and_id_ne(resource_code.clone(), id).await? {
            Err(MyError::ServerError(format!(
                "资源编码[{}]已存在",
                resource_code
            )))
        } else {
            Ok(resource_code)
        }
    }
}
